#pragma once

#include <memory>

#include <stack>

#include "Containers/Containers.h"
#include "Object/Object.h"

class CByteCodeFile;
class CScriptDecoratedType;
class CByteCodeReader;
class CBreakpointSlot;
class CScriptFunction;

class CFunctionInterpreter
{
public:  
    CFunctionInterpreter(const TVector<std::shared_ptr<CBreakpointSlot>> & BreakpointSlots
        ,CScriptFunction* InFunction
    );

    /// @return  Return value of function
    CAny RunScript();

    std::stack<CAny> ValueStack;

    TVector<CAny> VariableStack;

    TVector<CAny> ArgumentStack;

    CString Error;

    std::shared_ptr<CByteCodeFile> ScriptFile;

    const TVector<std::shared_ptr<CBreakpointSlot>> & BreakpointSlots;

    // position in bytecode file
    uint32_t ByteCodeStart; 

    // line start position relative to ByteCodeStart
    TVector<uint32_t> FunctionLines;

    //byte code file line , not source code line
    uint32_t LineIndex=0;

    CScriptFunction* Function=nullptr;
protected:

    /// @return  Succeed
    bool ExecInstruction();

    std::shared_ptr<CByteCodeReader> ScriptFileReader;


    void CallFunction(CFunction* InFunction);

    //bool bFunctionEnded=false;

    void GoNextLine();

    void GoEndLine();

    void GoLine(uint32_t InLine);

    void ThrowException(const CString & InError);
};